/*!
\copyright  Copyright (c) 2023 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file
\brief      List API
*/

#include "list.h"
#include "list_interface.h"
#include "list_debug.h"

#include <stdlib.h>
#include <panic.h>
#include <logging.h>


typedef struct _list_t {
    const list_interface_t* interface;
    void* list;
} _list_t;

const list_config_t default_config = {
    .type = list_type_linked_single,
    .element_store = {
        .type = list_store_reference
    },
};

const list_config_t* ListGetDefaultConfig(void)
{
    return &default_config;
}

list_t ListCreate(const list_config_t* config)
{
    _list_t* list = PanicNull(calloc(1, sizeof(_list_t)));

    if (!config)
    {
        config = ListGetDefaultConfig();
    }

    list->interface = ListGetInterface(config->type);

    list->list = list->interface->ListCreate(config);

    return list;
}

void ListDestroy(list_t *list)
{
    ASSERT_NOT_NULL(*list);

    (*list)->interface->ListDestroy(&(*list)->list);

    free(*list);
    *list = NULL;
}

void ListPrependWithSize(list_t list, void* element, size_t size)
{
    ASSERT_NOT_NULL(list);

    const list_config_t* config = list->interface->ListGetConfig(list->list);
    if(config->element_store.type != list_store_variable_size_element)
    {
        DEBUG_LOG_PANIC("%s: This API is only allowed for lists of variable size elements", __func__);
    }

    list->interface->ListPrependWithSize(list->list, element, size);
}

void ListAppendWithSize(list_t list, void* element, size_t size)
{
    ASSERT_NOT_NULL(list);

    const list_config_t* config = list->interface->ListGetConfig(list->list);
    if(config->element_store.type != list_store_variable_size_element)
    {
        DEBUG_LOG_PANIC("%s: This API is only allowed for lists of variable size elements", __func__);
    }

    list->interface->ListAppendWithSize(list->list, element, size);
}

void ListPrepend(list_t list, void* element)
{
    ASSERT_NOT_NULL(list);
    list->interface->ListPrepend(list->list, element);
}

void ListAppend(list_t list, void* element)
{
    ASSERT_NOT_NULL(list);
    list->interface->ListAppend(list->list, element);
}

void ListDeleteNode(list_t list, list_node_t* node)
{
    ASSERT_NOT_NULL(list);
    ASSERT_NOT_NULL(node);
    list->interface->ListDeleteNode(list->list, node);
}

bool ListIsEmpty(list_t list)
{
    ASSERT_NOT_NULL(list);
    return list->interface->ListIsEmpty(list->list);
}

list_node_t ListGetHead(const list_t list)
{
    ASSERT_NOT_NULL(list);
    return list->interface->ListGetHead(list->list);
}

list_node_t ListGetTail(const list_t list)
{
    ASSERT_NOT_NULL(list);
    return list->interface->ListGetTail(list->list);
}

list_node_t ListGetNext(const list_t list, list_node_t node)
{
    ASSERT_NOT_NULL(list);
    ASSERT_NOT_NULL(node);
    return list->interface->ListGetNext(list->list, node);
}

void* ListGetElement(const list_t list, list_node_t node)
{
    ASSERT_NOT_NULL(list);
    ASSERT_NOT_NULL(node);
    return list->interface->ListGetElement(list->list, node);
}

size_t ListGetElementSize(const list_t list, list_node_t node)
{
    ASSERT_NOT_NULL(list);
    ASSERT_NOT_NULL(node);
    return list->interface->ListGetElementSize(list->list, node);
}